﻿using hyjx.comm;
using hyjx.comm.Exceptions;
using hyjx.comm.Types;
using Hyjx.MixerService.Configs;
using Hyjx.MixerService.Exceptions;
using Hyjx.MixerService.Objects;
using S7.Net;
using Serilog;
using Serilog.Events;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Security;
using System.Text;

namespace Hyjx.MixerService
{
    public class Mixer : BackgroundService
    {
        private string SerilogOutputTemplate = "[{Timestamp:yyy/MM/dd HH:mm:ss.fff} {Level:u3}] {Message:lj} {NewLine}{Exception}";
        private int inCheckMesOnline;

        readonly ILogger<Mixer>? _logger;
        readonly IConfiguration? _config;
        int _checkMesOnlineSeconds;
        int _reportMixerStatusSeconds;
        int _reportMixerAlarmSeconds;
        int _stepStatusChangedSeconds;

        int _checkDataSeconds;

        IEnumerable<MixerConfig>? enableLines;
        string? _webApiBaseUrl;
        string? _healthCheck;
        AppHttp? _http;
        MixerConfig[]? _mixers;
        bool _mesOnline;
        bool _isPositive;

        readonly ConcurrentDictionary<string, MixerService> mixerServices = new();
        readonly ConcurrentDictionary<string, int> _mixerStatusTimes = new();
        readonly ConcurrentDictionary<string, int> _stepChangedTimes = new();
        readonly ConcurrentDictionary<string, int> _alarmTimes = new();
        readonly ConcurrentDictionary<string, int> _alarmCollectionTimes = new(); // 新报警系统报警采集频率集合
        readonly ConcurrentDictionary<string, int> _alarmReportTimes = new(); // 新报经系统报警上报频率集合
        readonly ConcurrentDictionary<string, int> _saveMixerStatusTimes = new();

        int _alarmCollectionSeconds;
        int _alarmReportSeconds;

        public Mixer(IConfiguration config, ILogger<Mixer> logger)
        {
            try
            {
                _config = config;
                _logger = logger;

                Log.Logger = new LoggerConfiguration()
                            .Enrich.FromLogContext()
                            .MinimumLevel.Debug()
                            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p =>
                            p.Level == LogEventLevel.Information).
                            WriteTo.File($"{AppDomain.CurrentDomain.BaseDirectory}/Log/{DateTime.Now:yyyyMM}/Info-.txt", rollingInterval: RollingInterval.Day,
                            rollOnFileSizeLimit: true,
                            fileSizeLimitBytes: 30_000_000,
                            retainedFileTimeLimit: TimeSpan.FromDays(90),
                            shared: true,
                            outputTemplate: SerilogOutputTemplate))
                            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Error).WriteTo.File($"{AppDomain.CurrentDomain.BaseDirectory}/Log/{DateTime.Now:yyyyMM}/Error-.txt", rollingInterval: RollingInterval.Day, rollOnFileSizeLimit: true,
                            fileSizeLimitBytes: 30_000_000,
                            retainedFileTimeLimit: TimeSpan.FromDays(90),
                            shared: true,
                            outputTemplate: SerilogOutputTemplate))
                            .CreateLogger();
            }
            catch (Exception ex)
            {
                Log.Error(ex, "搅拌系统服务无法启动");
            }
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            if (_config == null || _logger == null)
                return Task.CompletedTask;

            _checkMesOnlineSeconds = _config.GetValue<int>("CheckMesOnlineSeconds");
            _reportMixerStatusSeconds = _config.GetValue<int>("ReportMixerStatusSeconds");
            _reportMixerAlarmSeconds = _config.GetValue<int>("ReportMixerAlarmSeconds");
            _stepStatusChangedSeconds = _config.GetValue<int>("StepStatusChangedSeconds");

            _checkDataSeconds = _config.GetValue<int>("CheckDataSeconds");

            _webApiBaseUrl = _config.GetValue<string>("WebApiBaseUrl");
            _healthCheck = _config.GetValue<string>("HealthCheck");
            _mixers = _config.GetSection("Mixers").Get<MixerConfig[]>();
            _alarmCollectionSeconds = _config.GetValue<int>("AlarmCollectionSeconds");
            _alarmReportSeconds = _config.GetValue<int>("AlarmReportSeconds");
            _isPositive = _config.GetValue<bool>("IsPositive");
            _http = new(_logger);

            if (_mixers != null)
            {
                enableLines = _mixers.Where(p => p.IsEnabled);
                foreach (var item in enableLines)
                {
                    if (item.Plcs == null || !item.Plcs.Any())
                        continue;

                    foreach (var plc in item.Plcs.Where(p => p.IsEnabled))
                    {
                        _mixerStatusTimes.TryAdd(plc.ControlDevice, 1);
                        _stepChangedTimes.TryAdd(plc.ControlDevice, 1);
                        _alarmTimes.TryAdd(plc.ControlDevice, 1);
                        _alarmCollectionTimes.TryAdd(plc.ControlDevice, 1);
                        _alarmReportTimes.TryAdd(plc.ControlDevice, 1);
                        _saveMixerStatusTimes.TryAdd(plc.ControlDevice, 1);

                        mixerServices.TryAdd(plc.ControlDevice, new MixerService(_config, plc, new S7Protocol(plc.CpuType, plc.Ip, plc.Rack, plc.Slot), _http));
                    }
                }
            }
            Log.Information("搅拌系统服务已启动。");
            return base.StartAsync(cancellationToken);
        }

        public override Task StopAsync(CancellationToken cancellationToken)
        {
            _checkMesOnlineSeconds = 0;
            _reportMixerStatusSeconds = 0;
            _reportMixerAlarmSeconds = 0;
            _stepStatusChangedSeconds = 0;
            _alarmCollectionSeconds = 0;
            _alarmReportSeconds = 0;
            _webApiBaseUrl = null;
            _http = null;
            _mixers = null;
            enableLines = null;

            _mixerStatusTimes.Clear();
            _stepChangedTimes.Clear();
            _alarmTimes.Clear();
            _alarmCollectionTimes.Clear();
            _alarmReportTimes.Clear();
            _saveMixerStatusTimes.Clear();

            foreach (var mixerService in mixerServices)
            {
                mixerService.Value.Disconnect();
            }
            mixerServices.Clear();

            Log.Information("搅拌系统服务已停止。");
            Log.CloseAndFlush();

            return base.StopAsync(cancellationToken);
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // MES在线检查
            // 上报各搅拌机状态（207）
            // 上报各搅拌机报警（206）
            // 工步状态变更（205）
            int elapsedCheckMesOnlineTime = 1;

            while (!stoppingToken.IsCancellationRequested)
            {
                try
                {
                    if (elapsedCheckMesOnlineTime == _checkMesOnlineSeconds || !_mesOnline)
                    {
                        Task.Run(CheckMesOnline, stoppingToken);// MES在线检查
                        elapsedCheckMesOnlineTime = 1;
                    }
                    else
                        elapsedCheckMesOnlineTime++;

                    if (enableLines is not null)
                    {
                        foreach (var line in enableLines)
                        {
                            if (line.Plcs is not null)
                            {
                                foreach (var plc in line.Plcs)
                                {
                                    if (plc.IsEnabled && (plc.FeatureType == PlcFeatureTypes.Mix || plc.FeatureType == PlcFeatureTypes.Frl) && mixerServices.TryGetValue(plc.ControlDevice, out var mixerService) && mixerService is not null)
                                    {
                                        mixerService.MesOnline = _mesOnline;

                                        if (!mixerService.IsConnected)
                                        {
                                            Task.Run(mixerService.Connect, stoppingToken);
                                            continue;
                                        }

                                        Task.Run(mixerService.PlcIsMesMode, stoppingToken);

                                        if (!mixerService.IsMesMode)
                                            continue;

                                        if (_alarmTimes.TryGetValue(plc.ControlDevice, out var alarmCount))
                                        {
                                            if (alarmCount == _reportMixerAlarmSeconds)
                                            {
                                                // 上报各搅拌机报警（206）
                                                Task.Run(mixerService.ReportMixerAlarm, stoppingToken);
                                                _alarmTimes.TryUpdate(plc.ControlDevice, 1, alarmCount);
                                            }
                                            else
                                            {
                                                _alarmTimes.TryUpdate(plc.ControlDevice, alarmCount + 1, alarmCount);
                                            }
                                        }

                                        if (_stepChangedTimes.TryGetValue(plc.ControlDevice, out int stepCount))
                                        {
                                            if (stepCount == _stepStatusChangedSeconds)
                                            {
                                                // 工步状态变更（205）
                                                Task.Run(mixerService.StepStatusChanged, stoppingToken);
                                                Task.Run(mixerService.StepFinishedMesValid, stoppingToken);
                                                _stepChangedTimes.TryUpdate(plc.ControlDevice, 1, stepCount);
                                            }
                                            else
                                            {
                                                _stepChangedTimes.TryUpdate(plc.ControlDevice, stepCount + 1, stepCount);
                                            }
                                        }

                                        if (_mixerStatusTimes.TryGetValue(plc.ControlDevice, out int statusCount))
                                        {
                                            if (statusCount == _reportMixerStatusSeconds)
                                            {
                                                // 上报各搅拌机状态（207）
                                                Task.Run(mixerService.ReportMixerStatus, stoppingToken);
                                                _mixerStatusTimes.TryUpdate(plc.ControlDevice, 1, statusCount);
                                            }
                                            else
                                            {
                                                _mixerStatusTimes.TryUpdate(plc.ControlDevice, statusCount + 1, statusCount);
                                            }
                                        }

                                        if (_alarmCollectionTimes.TryGetValue(plc.ControlDevice, out int alarmCollectionCount))
                                        {
                                            // 采集设备报警接口的报警数据
                                            if (alarmCollectionCount == _alarmCollectionSeconds)
                                            {
                                                Task.Run(() => mixerService.CollectionAlarmsForMes(), stoppingToken);
                                                _alarmCollectionTimes.TryUpdate(plc.ControlDevice, 1, alarmCollectionCount);
                                            }
                                            else
                                                _alarmCollectionTimes.TryUpdate(plc.ControlDevice, alarmCollectionCount + 1, alarmCollectionCount);
                                        }

                                        if (_alarmReportTimes.TryGetValue(plc.ControlDevice, out int alarmReport))
                                        {
                                            // 上传设备报警 671
                                            if (alarmReport == _alarmReportSeconds)
                                            {
                                                //StreamWriteText($"#{DateTime.Now}: {plc.ControlDevice} 即将执行 671 上报");
                                                Task.Run(() => mixerService.ReportAlarmSys(line.Line ?? string.Empty, _isPositive), stoppingToken);
                                                _alarmReportTimes.TryUpdate(plc.ControlDevice, 1, alarmReport);
                                            }
                                            else
                                                _alarmReportTimes.TryUpdate(plc.ControlDevice, alarmReport + 1, alarmReport);
                                        }

                                        if (_saveMixerStatusTimes.TryGetValue(plc.ControlDevice, out int saveStatusCount))
                                        {
                                            if (saveStatusCount == _checkDataSeconds)
                                            {
                                                // 保存各搅拌机过程参数数据
                                                Task.Run(mixerService.SaveMixerStatus, stoppingToken);
                                                _saveMixerStatusTimes.TryUpdate(plc.ControlDevice, 1, saveStatusCount);
                                            }
                                            else
                                            {
                                                _saveMixerStatusTimes.TryUpdate(plc.ControlDevice, saveStatusCount + 1, saveStatusCount);
                                            }
                                        }

                                        Task.Run(mixerService.WriteMesOnline, stoppingToken);

                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception err)
                {
                    Log.Error(err, "搅拌服务运行异常");
                }

                Thread.Sleep(TimeSpan.FromSeconds(1));
            }

            return Task.CompletedTask;
        }

        private async void CheckMesOnline()
        {
            if (_http == null || string.IsNullOrEmpty(_webApiBaseUrl) || _mixers == null || !_mixers.Any(p => p.IsEnabled == true) || _config == null || _logger == null)
                return;

            try
            {
                if (Interlocked.Exchange(ref inCheckMesOnline, 1) == 0)
                {
                    _mesOnline = await _http.CheckMesHeartBeat(_webApiBaseUrl + _healthCheck);
                }
            }
            catch (Exception err)
            {
                Log.Error($"Mes 心跳检测异常,信息:{err.Message}");
            }
            finally
            {
                Interlocked.Exchange(ref inCheckMesOnline, 0);
            }
        }

        void StreamWriteText(string content)
        {
            try
            {
                string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestTempLog.txt");
                using StreamWriter stream = new(path, true, Encoding.UTF8);
                stream.WriteLine(content);
            }
            catch (Exception ex)
            {

            }
        }
    }


}
